package com.xm.security.core;

import com.xm.common.Constants;

import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

/**
 * 描述: 功能描述：非对称算法-RSA,公钥加密-私钥解密，私钥加密-公钥解密
 *
 * @author chen-guipeng
 * @date 2022/7/21
 */
public abstract class RSA {
    /**
     * 密钥算法
     */
    private static final String KEY_ALGORIGTHM = "RSA";

    private static final String CIPHER_ALGORITHM_ECB1 = "RSA/ECB/PKCS1Padding";

    /**
     * 默认key长度
     */
    private static final int DEFAULT_KEY_SIZE = 1024;

    /**
     * 生成密钥对
     *
     * @return
     * @throws Exception
     */
    public static KeyPair getKeyPair(int keySize) throws Exception {
        if (keySize <= 0) {
            keySize = DEFAULT_KEY_SIZE;
        }
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORIGTHM);
        // 设置密钥长度
        keyPairGen.initialize(keySize);

        return keyPairGen.generateKeyPair();
    }

    /**
     * 公钥加密
     *
     * @param data 待加密数据
     * @param key  公钥
     * @return
     * @throws Exception
     */
    public static String encryptByPublicKey(String data, String key) throws Exception {
        return Base64.getEncoder().encodeToString(encodeByPublicKey(data.getBytes(Constants.DEFAULT_ENCODING), toBytes(key)));
    }

    /**
     * 公钥加密
     *
     * @param data 待加密数据
     * @param key  公钥
     * @return
     * @throws Exception
     */
    public static byte[] encodeByPublicKey(byte[] data, byte[] key) throws Exception {
        return codeByPublicKey(data, key, Cipher.ENCRYPT_MODE);
    }

    /**
     * 私钥加密
     *
     * @param data 待加密数据
     * @param key  私钥
     * @return
     * @throws Exception
     */
    public static String encryptByPrivateKey(String data, String key) throws Exception {
        return Base64.getEncoder().encodeToString(encodeByPrivateKey(data.getBytes(Constants.DEFAULT_ENCODING), toBytes(key)));
    }

    /**
     * 私钥加密
     *
     * @param data 待加密数据
     * @param key  私钥
     * @return
     * @throws Exception
     */
    public static byte[] encodeByPrivateKey(byte[] data, byte[] key) throws Exception {
        return codeByPrivateKey(data, key, Cipher.ENCRYPT_MODE);
    }

    /**
     * 公钥解密
     *
     * @param data 待解密数据
     * @param key  公钥
     * @return
     * @throws Exception
     */
    public static String decryptByPublicKey(String data, String key) throws Exception {
        return new String(decodeByPublicKey(toBytes(data), toBytes(key)), Constants.DEFAULT_ENCODING);
    }

    /**
     * 公钥解密
     *
     * @param data 待解密数据
     * @param key  公钥
     * @return
     * @throws Exception
     */
    public static byte[] decodeByPublicKey(byte[] data, byte[] key) throws Exception {
        return codeByPublicKey(data, key, Cipher.DECRYPT_MODE);
    }

    /**
     * 私钥解密
     *
     * @param data 待解密数据
     * @param key  私钥
     * @return
     * @throws Exception
     */
    public static String decodeByPrivateKey(String data, String key) throws Exception {
        return new String(decodeByPrivateKey(toBytes(data), toBytes(key)), Constants.DEFAULT_ENCODING);
    }

    /**
     * 私钥解密
     *
     * @param data 待解密数据
     * @param key  私钥
     * @return
     * @throws Exception
     */
    public static byte[] decodeByPrivateKey(byte[] data, byte[] key) throws Exception {
        return codeByPrivateKey(data, key, Cipher.DECRYPT_MODE);
    }

    /**
     * base64字符串转换成bytes
     *
     * @param str
     * @return
     */
    private static byte[] toBytes(String str) {
        if (str == null) {
            return null;
        }
        return Base64.getDecoder().decode(str);
    }

    /**
     * 公钥加密解密
     *
     * @param data
     * @param key
     * @param mode
     * @return
     * @throws Exception
     */
    private static byte[] codeByPublicKey(byte[] data, byte[] key, int mode) throws Exception {
        // 取得公钥
        KeyFactory factory = KeyFactory.getInstance(KEY_ALGORIGTHM);
        // 生成公钥
        PublicKey pubKey = factory.generatePublic(new X509EncodedKeySpec(key));
        // 加密或解密数据
        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM_ECB1);
        cipher.init(mode, pubKey);

        return cipher.doFinal(data);
    }

    /**
     * 私钥加密和解密
     *
     * @param data
     * @param key
     * @param mode
     * @return
     * @throws Exception
     */
    private static byte[] codeByPrivateKey(byte[] data, byte[] key, int mode) throws Exception {
        // 取得 私钥
        KeyFactory factory = KeyFactory.getInstance(KEY_ALGORIGTHM);
        PrivateKey priKey = factory.generatePrivate(new PKCS8EncodedKeySpec(key));

        // 加密或解密数据
        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM_ECB1);
        cipher.init(mode, priKey);

        return cipher.doFinal(data);
    }

}
